# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

from .automatedproperties import AutomatedProperties
from .utils import job_obj_path_generate
from . import cfg
from .cfg import JOB_INTERFACE
import dbus
import threading
from . import background


# noinspection PyPep8Naming
class JobState(object):
	def __init__(self, request=None):
		self.rlock = threading.RLock()

		self._percent = 0
		self._complete = False
		self._request = request
		self._cond = threading.Condition(self.rlock)
		self._ec = 0
		self._stderr = ''

		# This is an lvm command that is just taking too long and doesn't
		# support background operation
		if self._request:
			# Faking the percentage when we don't have one
			self._percent = 1

	@property
	def Percent(self):
		with self.rlock:
			return self._percent

	@Percent.setter
	def Percent(self, value):
		with self.rlock:
			self._percent = value

	@property
	def Complete(self):
		with self.rlock:
			if self._request:
				self._complete = self._request.is_done()

			return self._complete

	@Complete.setter
	def Complete(self, value):
		with self.rlock:
			self._complete = value
			self._percent = 100
			self._cond.notify_all()

	@property
	def GetError(self):
		with self.rlock:
			if self.Complete:
				if self._request:
					(rc, error) = self._request.get_errors()
					return (rc, str(error))
				else:
					return (self._ec, self._stderr)
			else:
				return (-1, 'Job is not complete!')

	def set_result(self, ec, msg):
		with self.rlock:
			self.Complete = True
			self._ec = ec
			self._stderr = msg

	def dtor(self):
		with self.rlock:
			self._request = None

	def Wait(self, timeout):
		try:
			with self._cond:
				# Check to see if we are done, before we wait
				if not self.Complete:
					if timeout != -1:
						self._cond.wait(timeout)
					else:
						self._cond.wait()
				return self.Complete
		except RuntimeError:
			return False

	@property
	def Result(self):
		with self.rlock:
			if self._request:
				return self._request.result()
			return '/'


# noinspection PyPep8Naming
class Job(AutomatedProperties):
	_Percent_meta = ('d', JOB_INTERFACE)
	_Complete_meta = ('b', JOB_INTERFACE)
	_Result_meta = ('o', JOB_INTERFACE)
	_GetError_meta = ('(is)', JOB_INTERFACE)

	def __init__(self, request, job_state=None):
		super(Job, self).__init__(job_obj_path_generate())
		self.set_interface(JOB_INTERFACE)

		if job_state:
			self.state = job_state
		else:
			self.state = JobState(request)

	@property
	def Percent(self):
		return dbus.Double(float(self.state.Percent))

	@Percent.setter
	def Percent(self, value):
		self.state.Percent = value

	@property
	def Complete(self):
		return dbus.Boolean(self.state.Complete)

	@Complete.setter
	def Complete(self, value):
		self.state.Complete = value

	@property
	def GetError(self):
		return dbus.Struct(self.state.GetError, signature="(is)")

	def set_result(self, ec, msg):
		self.state.set_result(ec, msg)

	@dbus.service.method(dbus_interface=JOB_INTERFACE)
	def Remove(self):
		if self.state.Complete:
			cfg.om.remove_object(self, True)
			self.state.dtor()
		else:
			raise dbus.exceptions.DBusException(
				JOB_INTERFACE, 'Job is not complete!')

	@dbus.service.method(dbus_interface=JOB_INTERFACE,
							in_signature='i',
							out_signature='b',
							async_callbacks=('cb', 'cbe'))
	def Wait(self, timeout, cb, cbe):
		background.add_wait(self, timeout, cb, cbe)

	@property
	def Result(self):
		return dbus.ObjectPath(self.state.Result)

	@property
	def lvm_id(self):
		return str(id(self))

	@property
	def Uuid(self):
		import uuid
		return uuid.uuid1()
