class SubprocessTask:
	"""monitor a process and show its progress as a Chimera task

	Provide a SubprocessMonitor.Popen interface so an instance
	may be handed to code that is expecting a Subprocess.Popen
	return value.
	"""

	def __init__(self, text, subproc, task=None, afterCB=None, *args, **kw):
		from tasks import Task
		self._subproc = subproc
		self._aborted = False
		if not isinstance(text, basestring):
			text = ' '.join(text)
		if task is None:
			self._ownTask = True
			self._task = Task(text, self.cancelCB, self.statusCB)
			self._text = ""
		else:
			self._ownTask = False
			task.addCallbacks(self.cancelCB, self.statusCB)
			self._task = task
			self._text = text
		self._after = afterCB
		self.returncode = None

	def poll(self):
		return self._subproc.poll()

	def wait(self):
		import chimera
		from chimera import tkgui
		from chimera.update import UPDATE_INTERVAL
		from time import sleep
		interval = UPDATE_INTERVAL / 1000.0	# msec -> sec
		self.statusCB()
		while self.returncode is None and not self._aborted:
			sleep(interval)
			self.statusCB()
			tkgui.update_windows()
		if self._aborted:
			from chimera import NonChimeraError
			raise NonChimeraError("Raytrace cancelled by user")
		return self.returncode

	def statusCB(self):
		if not self._subproc:
			return
		progress = self._subproc.progress()
		self.returncode = self._subproc.poll()
		if self.returncode is not None:
			self.finished()
			return
		if self._text:
			msg = "%s: %d%% complete" % (self._text,
							int(progress * 100))
		else:
			msg = "%d%% complete" % int(progress * 100)
		self._task.updateStatus(msg)

	def cancelCB(self):
		print "SubprocessTask canceled"
		# kill/terminate process
		if self._subproc:
			# workaround bug 6451 (_subproc should never be None)
			self._subproc.terminate()
		self._aborted = True
		self.finished()

	def finished(self, value=None):
		if self._aborted:
			status = "aborted"
		else:
			status = "completed"
		if self._text:
			msg = "%s: %s" % (self._text, status)
		else:
			msg = status
		self._task.updateStatus(msg)
		if self._ownTask:
			self._task = None
		else:
			self._task.removeCallbacks(self.cancelCB, self.statusCB)
		self._subproc = None
		if self._after:
			self._after(self._aborted)
class SubprocessTask:
    """monitor a process and show its progress as a Chimera task

	Provide a SubprocessMonitor.Popen interface so an instance
	may be handed to code that is expecting a Subprocess.Popen
	return value.
	"""
    def __init__(self, text, subproc, task=None, afterCB=None, *args, **kw):
        from tasks import Task
        self._subproc = subproc
        self._aborted = False
        if not isinstance(text, basestring):
            text = ' '.join(text)
        if task is None:
            self._ownTask = True
            self._task = Task(text, self.cancelCB, self.statusCB)
            self._text = ""
        else:
            self._ownTask = False
            task.addCallbacks(self.cancelCB, self.statusCB)
            self._task = task
            self._text = text
        self._after = afterCB
        self.returncode = None

    def poll(self):
        return self._subproc.poll()

    def wait(self):
        import chimera
        from chimera import tkgui
        from chimera.update import UPDATE_INTERVAL
        from time import sleep
        interval = UPDATE_INTERVAL / 1000.0  # msec -> sec
        self.statusCB()
        while self.returncode is None and not self._aborted:
            sleep(interval)
            self.statusCB()
            tkgui.update_windows()
        if self._aborted:
            from chimera import NonChimeraError
            raise NonChimeraError("Raytrace cancelled by user")
        return self.returncode

    def statusCB(self):
        if not self._subproc:
            return
        progress = self._subproc.progress()
        self.returncode = self._subproc.poll()
        if self.returncode is not None:
            self.finished()
            return
        if self._text:
            msg = "%s: %d%% complete" % (self._text, int(progress * 100))
        else:
            msg = "%d%% complete" % int(progress * 100)
        self._task.updateStatus(msg)

    def cancelCB(self):
        print "SubprocessTask canceled"
        # kill/terminate process
        if self._subproc:
            # workaround bug 6451 (_subproc should never be None)
            self._subproc.terminate()
        self._aborted = True
        self.finished()

    def finished(self, value=None):
        if self._aborted:
            status = "aborted"
        else:
            status = "completed"
        if self._text:
            msg = "%s: %s" % (self._text, status)
        else:
            msg = status
        self._task.updateStatus(msg)
        if self._ownTask:
            self._task = None
        else:
            self._task.removeCallbacks(self.cancelCB, self.statusCB)
        self._subproc = None
        if self._after:
            self._after(self._aborted)