import decimal

def dec(value):
	"""Return the decimal value"""
	if value is None:
		return value
	else:
		return decimal.Decimal(str(value))

class PCygniParameter:
	def __init__(self, name, min, max, step=None, nstep=None, unit="", log_mode = False):
		self.name     = name
		self._unit    = unit
		self._min     = min
		self._max     = max
		self.log_mode = log_mode
		
		if self.unit:
			self.x_axis_label = "%s" % self.unit
			self.y_axis_label = "%s" % self.unit
		else:
			self.unit = ""
			self.x_axis_label = "%s" % self.name
			self.y_axis_label = "%s" % self.name
		
		# Setting step and nstep
		# Only step or nstep at a time
		if step and nstep:
			raise ValueError("You cannot define step and nstep in the same time.")
		
		# At least step or nstep
		if step is None and nstep is None :
			raise ValueError("You must define step or nstep.")

		self._step  = step
		self._nstep = nstep

	# Unit
	def get_unit(self):
		if not self._unit:
			if self.name.lower().startswith("n"):
				unit = " (cm-2)"
			elif self.name.lower().startswith("tex"):
				unit = " (K)"
			elif self.name.lower().startswith("tkin"):
				unit = " (K)"
			else:
				unit = ""
		else:
			unit = self._unit

		if self.log_mode:
			return "Log[%s%s]" % (self.name, unit)
		else:
			return "%s%s" % (self.name, unit)

	# TODO Fix set_unit
	def set_unit(self, value):
		# if self.log_mode:
		# 	self._unit = "Log[%s (%s)]" % (self.name, value)
		# else:
		# 	self._unit = "%s (%s)" % (self.name, value)
		self._unit = value

	# Min
	def get_min(self):
		if self.log_mode:
			return self._min.log10()
		else:
			return self._min

	def set_min(self, value):
		self._min = value
		
	# Max
	def get_max(self):
		if self.log_mode:
			return self._max.log10()
		else:
			return self._max

	def set_max(self, value):
		self._max = value
		
	# Step
	def get_step(self):
		if self.min == self.max:
			return 0

		if self._step and self._nstep is None:
			if self.log_mode:
				return (self.max - self.min)/(self.nstep - 1)
			else:
				return self._step

		elif self._nstep and self._step is None:
			# Prevent nstep from being lower than 1 (otherwise DivisionByZero)
			if self.nstep > 1:
				return (self.max - self.min)/(self.nstep - 1)
			else:
				return (self.max - self.min)

	def set_step(self, value):
		self._step = value
		
	# Nstep
	def get_nstep(self):
		if self.min == self.max:
			return 1
		
		if self._nstep and self._step is None:
			return int(self._nstep)

		elif self._step and self._nstep is None:
			if self.log_mode:
				c = decimal.ExtendedContext.copy()
				max = c.power(decimal.Decimal('10'), self.max)
				min = c.power(decimal.Decimal('10'), self.min)
				return int((max - min)/self._step) + 1
			else:
				return int((self.max - self.min)/self._step) + 1

	def set_nstep(self, value):
		self._nstep = int(value)

	step  = property(get_step , set_step)
	nstep = property(get_nstep, set_nstep)
	min   = property(get_min  , set_min)
	max   = property(get_max  , set_max)
	unit  = property(get_unit , set_unit)
		
	def __str__(self):
		if self.unit:
			return "%s is defined between [%g, %g] %s in %d steps." % (self.name, self.min, self.max, self.unit, self.nstep)
		else:
			return "%s is defined between [%g, %g] in %d steps." % (self.name, self.min, self.max, self.nstep)

	__repr__ = __str__

	def getValues(self):
		self.values = []
		for i in range(self.nstep):
			chi2 = self.min + self.step*i
			c = decimal.ExtendedContext.copy()
			if self.log_mode:
				chi2 = c.power(decimal.Decimal("10"), chi2)
			self.values.append(chi2)
		return self.values


# vim: set noet fdm=indent:
