local color
color = sorcery.lib.class {
	__tostring = function(self)
		-- return minetest.rgba(
		-- 	self.red,
		-- 	self.green,
		-- 	self.blue,
		-- 	self.alpha
		-- )
		local hex = function(val)
			return string.format('%02X',math.max(0,math.min(255,math.floor(val))))
		end
		local str = '#' ..
			hex(self.red) ..
			hex(self.green) ..
			hex(self.blue)
		if self.alpha then str = str .. hex(self.alpha) end
		return str
	end;

	__add = function(self, other)
		local sfac = (self.alpha or 255) / 255
		local ofac = (other.alpha or 255) / 255
		if self.alpha == other.alpha then
			sfac = 1 ofac = 1
		end

		local sr, sg, sb = other.red * ofac, other.blue * ofac, other.green * ofac
		local nr, ng, nb =  self.red * sfac,  self.blue * sfac,  self.green * sfac
		local saturate = function(a,b)
			return math.max(0, math.min(255, a+b))
		end
		local alpha = nil
		if self.alpha and other.alpha then
			alpha = saturate(self.alpha or 255, other.alpha or 255)
		end
		return color(
			saturate(sr, nr),
			saturate(sg, ng),
			saturate(sb, nb),
			alpha
		)
	end;
	
	cast = {
		number = function(n) return {
			red = n; green = n; blue = n;
		} end;
		table = function(t) return {
			red = t[1]; green = t[2]; blue = t[3];
		} end;
	};

	construct = function(r,g,b,a)
		local clip = function(v)
			return math.max(0,math.min(255,v))
		end;
		local warp = function(f)
			return function(self, ...)
				local n = color(self)
				f(n, ...)
				return n
			end;
		end;
		local new = {
			hex = function(self) return
				getmetatable(self).__tostring(self)
			end;

			fmt = function(self, text) return
				minetest.colorize(self:hex(), text)
			end;

			luminosity = function(self) return
				(self.red + self.green + self.blue) / 3
			end;

			readable = function(self, target)
				target = target or 200
				local lum = self:luminosity()
				if lum < target then
					local f = 1.0 + (target - lum) / 255
					local nc = self:brighten(f * 1.5)
					-- i don't know why the *1.5 is necessary. it's
					-- an ugly hack to work around broken math,
					-- because i'm too much of a mathtard to actually
					-- find what's wrong
					return nc
				else
					return self
				end
			end;

			bg = function(self, text) return
				text .. minetest.get_background_escape_sequence(self:hex())
			end;

			fade = warp(function(new, fac)
				new.alpha = math.min(255, (new.alpha or 255) * fac)
			end);

			brighten = warp(function(new, fac)
				local lum = new:luminosity()
				local newlum = lum * fac
				local delta = (newlum - lum)
				new.red   = clip(new.red   + delta)
				new.blue  = clip(new.blue  + delta)
				new.green = clip(new.green + delta)
			end);

			darken = warp(function(new, fac)
				new.red = clip(new.red - (new.red * fac))
				new.blue = clip(new.blue - (new.blue * fac))
				new.green = clip(new.green - (new.green * fac))
			end);
		}
		if g == nil then
			if type(r) == 'string' then
				assert(false) -- TODO parse color string
			elseif type(r) == 'table' then
				new.red = r[1]
				new.green = r[2]
				new.blue = r[3]
				new.alpha = r[4]
			else assert(false) end
		else
			new.red = r
			new.green = g
			new.blue = b
			new.alpha = a
		end
		return new
	end
}
return color
