local p = {}

function rgb2hsv(r, g, b)

   local max = math.max(r, g, b)
   local min = math.min(r, g, b)
   local c = max - min
   
   -- calculate hue
   local h
   if c == 0 then
       h = 0
   elseif max == r then
       h = 60 * (0 + ((g - b)/c))
   elseif max == g then
       h = 60 * (2 + ((b - r)/c))
   elseif max == b then
       h = 60 * (4 + ((r - g)/c))
   end
   if h < 0 then h = h + 360 end
   
   -- calculate value
   local v = max
   
   -- calculate luminance
   -- local l = (max + min) / 2
   
   -- calculate saturation
   local s
   if c == 0 then
       s = 0
   else
       s = c/v
   end
   
   return h, s, v

end

function hsv2rgb(h, s, v)

   local hi = math.floor(h / 60)
   local f = ((h / 60) - hi)
   
   local p = v * (1 - s)
   local q = v * (1 - s * f)
   local t = v * (1 - s * (1 - f))
   
   if hi == 1 then
       return q, v, p
   elseif hi == 2 then
       return p, v, t
   elseif hi == 3 then
       return p, q, v
   elseif hi == 4 then
       return t, p, v
   elseif hi == 5 then
       return v, p, q
   else
       return v, t, p
   end

end

function decodeRGBHex(rgb)

   local r = string.sub(rgb, 1, 2)
   local g = string.sub(rgb, 3, 4)
   local b = string.sub(rgb, 5, 6)
   return tonumber(r, 16), tonumber(g, 16), tonumber(b, 16)

end

function getRGB(args)

   local r, g, b, i
   if string.len(args[1]) == 6 then
       r, g, b = decodeRGBHex(args[1])
       i = 2
   else
       r = args[1]
       g = args[2]
       b = args[3]
       i = 4
   end
   return r / 255, g / 255, b / 255, i

end

--[[toHSV Description: Converts a RGB color to a HSV color.

Usage: 스크립트 오류: "HSV" 모듈이 없습니다. or 스크립트 오류: "HSV" 모듈이 없습니다.

Output: hue [0°..360°]/saturation [0..1]/value [0..1] ]] function p.toHSV(frame)

   local r, g, b = getRGB(frame.args)
   local h, s, v = rgb2hsv(r, g, b)
   return h .. "/" .. s .. "/" .. v

end

--[[hue Description: Returns the hue of a RGB color.

Usage: 스크립트 오류: "HSV" 모듈이 없습니다. or 스크립트 오류: "HSV" 모듈이 없습니다.

Output: hue [0°..360°] ]] function p.hue(frame)

   local r, g, b = getRGB(frame.args)
   local h, s, v = rgb2hsv(r, g, b)
   return h

end

--[[saturation Description: Returns the saturation of a RGB color.

Usage: 스크립트 오류: "HSV" 모듈이 없습니다. or 스크립트 오류: "HSV" 모듈이 없습니다.

Output: saturation [0..1] ]] function p.saturation(frame)

   local r, g, b = getRGB(frame.args)
   local h, s, v = rgb2hsv(r, g, b)
   return s

end

--[[value Description: Returns the hue of a RGB color.

Usage: 스크립트 오류: "HSV" 모듈이 없습니다. or 스크립트 오류: "HSV" 모듈이 없습니다.

Output: value [0..1] ]] function p.value(frame)

   local r, g, b = getRGB(frame.args)
   local h, s, v = rgb2hsv(r, g, b)
   return v

end

--[[saturate Description: Saturates a RGB color by a given factor.

Usage: 스크립트 오류: "HSV" 모듈이 없습니다. or 스크립트 오류: "HSV" 모듈이 없습니다. Optionally "factor" can be followed by another parameter with the value "hex" can be given to return the RGB color in a hexadecimal representation.

Output: saturated RGB ]] function p.saturate(frame)

   local r, g, b, i = getRGB(frame.args)
   -- convert to HSV
   local h, s, v = rgb2hsv(r, g, b)
   -- saturate
   s = s * frame.args[i]
   if s < 0 then
       s = 0
   elseif s > 1 then
       s = 1
   end
   -- convert back to RGB
   local r, g, b = hsv2rgb(h, s, v)
   r = math.floor(r * 255 + 0.5)
   g = math.floor(g * 255 + 0.5)
   b = math.floor(b * 255 + 0.5)
   -- return values
   if frame.args[i + 1] == "hex" then
       return string.format("%.2X%.2X%.2X", r, g, b)
   else
       return r .. "/" .. g .. "/" .. b
   end

end

--[[toRGB Description: Converts a HSV color to a RGB color.

Usage: 스크립트 오류: "HSV" 모듈이 없습니다. with H in [0°..360°], S in [0..1] and V in [0..1]. Optionally a 4th parameter with the value "hex" can be given to return the RGB color in a hexadecimal representation.

Output: R/G/B ]] function p.toRGB(frame)

   local r, g, b = hsv2rgb(frame.args[1], frame.args[2], frame.args[3])
   -- transform from real [0..1] to integer [0..255]
   r = math.floor(r * 255 + 0.5)
   g = math.floor(g * 255 + 0.5)
   b = math.floor(b * 255 + 0.5)
   -- return values
   if frame.args[4] == "hex" then
       return string.format("%.2X%.2X%.2X", r, g, b)
   else
       return r .. "/" .. g .. "/" .. b
   end

end

return p