
HSLColor = class("HSLColor")

-- 360, 1, 1
function HSLColor:new(h, s, l)
	local color = instance(self)
	color.h = h
	color.s = s
	color.l = l
	return color
end

function HSLColor:set(h,s,l)
	self.h = h
	self.s = s
	self.l = l
end

function HSLColor:addFromHsl(hslCol)
	self.h = (self.h + hslCol.h)%360
	self.s = math.clamp(self.s + hslCol.s, 0,1)
	self.l = math.clamp(self.l + hslCol.l, 0,1)
end

function HSLColor:setWith(color)
	local h,s,l = color:getHsl()
	self:set(h,s,l)
end

function HSLColor:getRgb()
    local chroma = (1 - math.abs(2 * self.l - 1)) * self.s
    local h = (self.h/60)
    local x =(1 - math.abs(h % 2 - 1)) * chroma
    local r, g, b = 0, 0, 0
    if h < 1 then
        r,g,b=chroma,x,0
    elseif h < 2 then
        r,b,g=x,chroma,0
    elseif h < 3 then
        r,g,b=0,chroma,x
    elseif h < 4 then
        r,g,b=0,x,chroma
    elseif h < 5 then
        r,g,b=x,0,chroma
    else
        r,g,b=chroma,0,x
    end
    local m = self.l - chroma/2
    return math.floor((r+m)*255),math.floor((g+m)*255),math.floor((b+m)*255)
end

function HSLColor:print(prefix)
	print((prefix or "")..":h:"..tostring(self.h).. " s:"..tostring(self.s).. " l:"..tostring(self.l))
end

Color = class("Color")

function Color:new(a, r, g, b)

	local color = instance(self)
	
	color.a = a or 255
	color.r = r or 255
	color.g = g or 255
	color.b = b or 255

	return color
end

function Color:newCopy(c)

	local color = instance(self)
	
	color.a = c.a
	color.r = c.r
	color.g = c.g
	color.b = c.b

	return color
end

function Color:getColor(index)
	if index == 1 then
		return self.a
	elseif index == 2 then
		return self.r
	elseif index == 3 then
		return self.g
	else
		return self.b
	end
end

function Color:fade(colorA, colorB, prg, factor)
	self.r = (colorA.r * (1-prg) + colorB.r * prg)*factor
	self.g = (colorA.g * (1-prg) + colorB.g * prg)*factor
	self.b = (colorA.b * (1-prg) + colorB.b * prg)*factor
end

function Color:getHsl()
	local h,s,l = 0,0,0
	local r = self.r / 256
	local g = self.g / 256
	local b = self.b / 256
	local minColor = math.min(r, g, b)
	local maxColor = math.max(r, g, b)
	if minColor == maxColor then
		h = 0
		s = 0
		l = r
	else
		l = (minColor + maxColor) / 2
		if l < 0.5 then 
			s = (maxColor - minColor) / (maxColor + minColor)
		else 
			s = (maxColor - minColor) / (2 - maxColor - minColor)
		end

		if r == maxColor then 
			h = (g -b) / (maxColor - minColor)
		elseif g == maxColor then 
			h = 2 + (b - r) / (maxColor - minColor)
		else 
			h = 4 + (r - g) / (maxColor - minColor)
		end

		h = h / 6

		if h < 0 then 
			h = h + 1 
		end
	end
	return math.floor(h*360), s, l
end

function Color:divideWith(color)
	self.a = math.round(math.clamp(self.a/color.a*255, 0, 255))
	self.r = math.round(math.clamp(self.r/color.r*255, 0, 255))
	self.g = math.round(math.clamp(self.g/color.g*255, 0, 255))
	self.b = math.round(math.clamp(self.b/color.b*255, 0, 255))
end

function Color:multiplyWith(color, factor)
	if factor then
		self.a = math.round(math.clamp(self.a*(1-factor) + factor*self.a*color.a/255, 0, 255))
		self.r = math.round(math.clamp(self.r*(1-factor) + factor*self.r*color.r/255, 0, 255))
		self.g = math.round(math.clamp(self.g*(1-factor) + factor*self.g*color.g/255, 0, 255))
		self.b = math.round(math.clamp(self.b*(1-factor) + factor*self.b*color.b/255, 0, 255))
	else
		self.a = math.round(math.clamp(self.a*color.a/255, 0, 255))
		self.r = math.round(math.clamp(self.r*color.r/255, 0, 255))
		self.g = math.round(math.clamp(self.g*color.g/255, 0, 255))
		self.b = math.round(math.clamp(self.b*color.b/255, 0, 255))
	end
end

function Color:tintWith(floatColor)
	self.a = math.round(math.clamp(self.a*floatColor.a, 0, 255))
	self.r = math.round(math.clamp(self.r*floatColor.r, 0, 255))
	self.g = math.round(math.clamp(self.g*floatColor.g, 0, 255))
	self.b = math.round(math.clamp(self.b*floatColor.b, 0, 255))
end

function Color:setWith(color, factor)
	if factor then
		self.a = self.a * (1-factor) + factor*color.a
		self.r = self.r * (1-factor) + factor*color.r
		self.g = self.g * (1-factor) + factor*color.g
		self.b = self.b * (1-factor) + factor*color.b
	else
		self.a = color.a
		self.r = color.r
		self.g = color.g
		self.b = color.b
	end
end

function Color:addWith(hslCol)
	local h,s,l = self:getHsl()
	h,s,l = h + hslCol.h,s + hslCol.s,l + hslCol.l

	local r, g, b = hslCol:getRgb()
	self.r, self.g, self.b = r,g,b
end

function Color:setFromHsl(hslCol)
	self.r, self.g, self.b = hslCol:getRgb()
end

function Color:set(a,r,g,b)
	self.a = a
	self.r = r
	self.g = g
	self.b = b
end

function Color:save(file)
	file:writeInt(self.a)
	file:writeInt(self.r)
	file:writeInt(self.g)
	file:writeInt(self.b)
end

function Color:load(file)

	local a,r,g,b = 0,0,0,0
	
	a = file:readInt()
	r = file:readInt()
	g = file:readInt()
	b = file:readInt()

	return Color:new(a,r,g,b)
end

function Color:getVariables()
	return self.a, self.r, self.g, self.b
end

function Color:print(prefix)
	print((prefix or "")..":"..tostring(self.a).. " "..tostring(self.r).. " "..tostring(self.g).. " "..tostring(self.b))
end

FloatColor = class("FloatColor")

function FloatColor:new(a, r, g, b)
	local color = instance(self)
	
	color.a = a
	color.r = r
	color.g = g
	color.b = b
	
	return color
end

function FloatColor:newCopy(c)

	local color = instance(self)
	
	color.a = c.a
	color.r = c.r
	color.g = c.g
	color.b = c.b

	return color
end

function FloatColor:getColor(index)
	if index == 1 then
		return self.a
	elseif index == 2 then
		return self.r
	elseif index == 3 then
		return self.g
	else
		return self.b
	end
end

function FloatColor:save(file)
	file:writeFloat(self.a)
	file:writeFloat(self.r)
	file:writeFloat(self.g)
	file:writeFloat(self.b)
end

function FloatColor:load(file)

	local a,r,g,b = 0,0,0,0
	
	a = file:readFloat()
	r = file:readFloat()
	g = file:readFloat()
	b = file:readFloat()

	return FloatColor:new(a,r,g,b)
end

ColorQuad = class("ColorQuad")

function ColorQuad:new(a, r, g, b)

	local color = instance(self)
	
	if type(a) == "table" then
		color.a = a
	else
		color.a = {a, a, a, a}
	end
	if type(r) == "table" then
		color.r = r
	else
		color.r = {r, r, r, r}
	end
	if type(g) == "table" then
		color.g = g
	else
		color.g = {g, g, g, g}
	end
	if type(b) == "table" then
		color.b = b
	else
		color.b = {b, b, b, b}
	end
	
	return color
end

function ColorQuad:newCopy(c)

	local color = instance(self)
	
	color.a = table.copy(c.a)
	color.r = table.copy(c.r)
	color.g = table.copy(c.g)
	color.b = table.copy(c.b)

	return color
end

function ColorQuad:getColorQuad(index)
	if index == 1 then
		return self.a
	elseif index == 2 then
		return self.r
	elseif index == 3 then
		return self.g
	else
		return self.b
	end
end

function ColorQuad:save(file)
	for i=1, 4 do
		file:writeInt(self.a[i])
		file:writeInt(self.r[i])
		file:writeInt(self.g[i])
		file:writeInt(self.b[i])
	end
end

function ColorQuad:load(file)

	local a,r,g,b = {},{},{},{}
	
	for i=1, 4 do
		a[i] = file:readInt()
		r[i] = file:readInt()
		g[i] = file:readInt()
		b[i] = file:readInt()
	end
	
	return ColorQuad:new(a,r,g,b)
end