import math
from color import Color

class ColorWheel:
	@property
	def baseColor(self):
		return self._baseColor

	@property
	def hue(self):
		return [
			self.baseColor, self.addH(1.0 / 12), self.addH(2.0 / 12), self.addH(3.0 / 12), self.addH(4.0 / 12), self.addH(5.0 / 12),
			self.addH(-6.0 / 12), self.addH(-5.0 / 12), self.addH(-4.0 / 12), self.addH(-3.0 / 12), self.addH(-2.0 / 12), self.addH(-1.0 / 12)
		]

	@property
	def tone(self):
		return [self.addWhite(-2.0 / 16), self.addWhite(-1.0 / 16), self.baseColor, self.addWhite(1.0 / 16), self.addWhite(2.0 / 16)]

	@property
	def tone15(self):
		return [self.addWhite(-7.0 / 16), self.addWhite(-6.0 / 16), self.addWhite(-5.0 / 16), self.addWhite(-4.0 / 16), self.addWhite(-3.0 / 16), 
				self.addWhite(-2.0 / 16), self.addWhite(-1.0 / 16), self.baseColor, self.addWhite(1.0 / 16), self.addWhite(2.0 / 16),
				self.addWhite(3.0 / 16), self.addWhite(4.0 / 16), self.addWhite(5.0 / 16), self.addWhite(6.0 / 16), self.addWhite(7.0 / 16)]

	@property
	def complementaryColors(self):
		return [self.baseColor, self.addH(0.5)]

	@property
	def triadicColors(self):
		return [self.addH(-4.0 / 12), self.baseColor, self.addH(4.0 / 12)]

	@property
	def splitComplementaryColors(self):
		return [self.addH(-5.0 / 12), self.baseColor, self.addH(5.0 / 12)]

	@property
	def analogousColors(self):
		return [self.addH(-2.0 / 12), self.addH(-1.0 / 12), self.baseColor, self.addH(1.0 / 12), self.addH(2.0 / 12)]

	def __init__(self, c):
		self._baseColor = c
		self._r = c.r / 255.0
		self._g = c.g / 255.0
		self._b = c.b / 255.0

	@staticmethod
	def fromHsv(h, s, v):
		r, g, b = ColorWheel.hsvToRgb(h, s, v)
		c = Color.fromRgb(round(r * 255), round(g * 255), round(b * 255))
		return ColorWheel(c)

	def addWhite(self, value):
		r, g, b = (self._r + value, self._g + value, self._b + value)
		r = min(max(r, 0.0), 1.0)
		g = min(max(g, 0.0), 1.0)
		b = min(max(b, 0.0), 1.0)
		return self._fromRgb(r, g, b)

	def addH(self, value):
		h, s, v = ColorWheel.rgbToHsv(self._r, self._g, self._b)
		h = (h + value) % 1.0
		if h < 0.0:
			h += 1.0
		r, g, b = ColorWheel.hsvToRgb(h, s, v)
		return self._fromRgb(r, g, b)

	def addS(self, value):
		h, s, v = ColorWheel.rgbToHsv(self._r, self._g, self._b)
		s += value
		s = min(max(s, 0.0), 1.0)
		r, g, b = ColorWheel.hsvToRgb(h, s, v)
		return self._fromRgb(r, g, b)

	def addV(self, value):
		h, s, v = ColorWheel.rgbToHsv(self._r, self._g, self._b)
		v += value
		v = min(max(v, 0.0), 1.0)
		r, g, b = ColorWheel.hsvToRgb(h, s, v)
		return self._fromRgb(r, g, b)

	@staticmethod
	def rgbToHsv(r, g, b):
		if r < 0.0 or r > 1.0:
			raise ValueError()
		if g < 0.0 or g > 1.0:
			raise ValueError()
		if b < 0.0 or b > 1.0:
			raise ValueError()
		cmax = max(r, g, b)
		cmin = min(r, g, b)
		h = cmax - cmin
		if h > 0.0:
			if cmax == r:
				h = (g - b) / h
				if h < 0.0:
					h += 6.0
			elif cmax == g:
				h = 2.0 + (b - r) / h
			else:
				h = 4.0 + (r - g) / h
		h /= 6.0
		s = cmax - cmin
		if cmax != 0.0:
			s /= cmax
		v = cmax
		return h, s, v

	@staticmethod
	def hsvToRgb(h, s, v):
		if h < 0.0 or h > 1.0:
			raise ValueError()
		if s < 0.0 or s > 1.0:
			raise ValueError()
		if v < 0.0 or v > 1.0:
			raise ValueError()
		r = v
		g = v
		b = v
		if s > 0.0:
			h *= 6.0
			i = math.floor(h)
			f = h - i
			if i == 1:
				r *= 1 - s * f
				b *= 1 - s
			elif i == 2:
				r *= 1 - s
				b *= 1 - s * (1 - f)
			elif i == 3:
				r *= 1 - s
				g *= 1 - s * f
			elif i == 4:
				r *= 1 - s * (1 - f)
				g *= 1 - s
			elif i == 5:
				g *= 1 - s
				b *= 1 - s * f
			else:
				g *= 1 - s * (1 - f)
				b *= 1 - s
		return r, g, b

	def _fromRgb(self, r, g, b):
		return Color.fromArgb(self.baseColor.a, round(r * 255), round(g * 255), round(b * 255))